import type { Logger } from 'bs-logger';
import { globsToMatcher } from 'jest-util';
import { type RawCompilerOptions, ConfigSet, type TsJestTransformOptions } from 'ts-jest';
import type { ParsedCommandLine } from 'typescript';

/**
 * Some NPM packages like `tslib` is distributed in such a way that `esbuild` cannot process it, so we fall back to use TypeScript API
 * @internal
 */
export const defaultProcessWithEsbuildPatterns = ['**/*.mjs'];

export class NgJestConfig extends ConfigSet {
    readonly processWithEsbuild: ReturnType<typeof globsToMatcher>;

    constructor(jestConfig: TsJestTransformOptions['config'] | undefined, parentLogger?: Logger | undefined) {
        super(jestConfig, parentLogger);
        const jestGlobalsConfig = jestConfig?.globals?.ngJest ?? Object.create(null);
        if (jestGlobalsConfig.processWithEsbuild) {
            this.logger.warn(
                'Specifying `processWithEsbuild` in `ngJest` config is deprecated and will be removed in the next major version. Please follow this documentation https://thymikee.github.io/jest-preset-angular/docs/getting-started/options#processing-with-esbuild instead.',
            );
        }
        this.processWithEsbuild = globsToMatcher([
            ...(jestGlobalsConfig.processWithEsbuild ?? []),
            ...defaultProcessWithEsbuildPatterns,
        ]);
    }

    /**
     * Override `ts-jest` behavior because we use `readConfiguration` which will read and resolve tsconfig.
     */
    protected _resolveTsConfig(compilerOptions?: RawCompilerOptions, resolvedConfigFile?: string): ParsedCommandLine {
        const result = super._resolveTsConfig(compilerOptions, resolvedConfigFile) as ParsedCommandLine;
        result.options.enableIvy = true;
        result.options.noEmitOnError = false;
        result.options.suppressOutputPathCheck = true;
        result.options.allowEmptyCodegenFiles = false;
        result.options.annotationsAs = 'decorators';
        result.options.enableResourceInlining = false;
        // Since we define preset default also transform `js` so we need to set `allowJs` true
        result.options.allowJs = true;

        return result;
    }
}
